/**
 @file sys_tmm_l3if.c

 @date 2018-9-21

 @version v1.0

 The file contains TMM L3IF APIs of sys layer
*/

/***************************************************************
 *
 * Header Files
 *
 ***************************************************************/
#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"
#include "sys_usw_common.h"
#include "sys_usw_ofb.h"
#include "sys_usw_chip.h"
#include "sys_usw_l3if.h"
#include "drv_api.h"
#include "sys_usw_wb_common.h"
#include "sys_tmm_l3if.h"
#include "sys_usw_register.h"
#include "sys_usw_ftm.h"

#ifdef EMULATION_ENV
#define SYS_L3IF_OFB_STEP 4
#else
#define SYS_L3IF_OFB_STEP 128
#endif
#define SYS_ROUTER_MAC_PROFILE_NUM  512
#define SYS_SYSTEM_RTMAC_INDEX  0

enum sys_l3if_ofb_blk_e
{
    SYS_L3IF_OFB_BLK_SUB_IF = 0, /*CTC_L3IF_TYPE_SUB_IF*/
    SYS_L3IF_OFB_BLK_PHY_IF,     /*CTC_L3IF_TYPE_PHY_IF*/
    SYS_L3IF_OFB_BLK_VLAN_IF,    /*CTC_L3IF_TYPE_VLAN_IF*/
    SYS_L3IF_OFB_BLK_SVC_IF,     /*CTC_L3IF_TYPE_SERVICE_IF*/
    SYS_L3IF_OFB_BLK_MAX
};
typedef enum sys_l3if_ofb_blk_e sys_l3if_ofb_blk_t;

sys_l3if_rmac_entry_master_t* p_tmm_l3if_rmac_entry_master[CTC_MAX_LOCAL_CHIP_NUM_PP] = {NULL};

STATIC uint32
_sys_usw_l3if_rmac_hash_make(sys_l3if_rmac_entry_t* p_rmac_entry)
{
    return ctc_hash_caculate(sizeof(uint32), &(p_rmac_entry->fpae.entry_id));
}

STATIC bool
_sys_usw_l3if_rmac_hash_cmp(sys_l3if_rmac_entry_t* p_rmac_entry0,
                              sys_l3if_rmac_entry_t* p_rmac_entry1)
{
    if (!p_rmac_entry0 || !p_rmac_entry1)
    {
        return FALSE;
    }

    if (p_rmac_entry1->fpae.entry_id== p_rmac_entry0->fpae.entry_id)
    {
        return TRUE;
    }

    return FALSE;
}

STATIC int32
_sys_tmm_l3if_tcam_rtmac_move(uint8 lchip, uint32 new_offset, uint32 old_offset)
{
    uint32 cmd = 0;
    DsRouterMacTcamKey_m  ds_key;
    DsRouterMacTcamKey_m  ds_mask;
    DsRouterMacTcamAd_m ds_ad;
    tbl_entry_t   tcam_key;

    sal_memset(&tcam_key, 0, sizeof(tcam_key));
    sal_memset(&ds_key, 0, sizeof(ds_key));
    sal_memset(&ds_mask, 0, sizeof(ds_mask));
    sal_memset(&ds_ad, 0, sizeof(ds_ad));

    /*move key*/
    tcam_key.data_entry = (uint32*)&ds_key;
    tcam_key.mask_entry = (uint32*)&ds_mask;
    cmd = DRV_IOR(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, old_offset, cmd, &tcam_key));
    cmd = DRV_IOW(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, new_offset, cmd, &tcam_key));

    sal_memset(&tcam_key, 0, sizeof(tcam_key));
    cmd = DRV_IOD(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, old_offset, cmd, &tcam_key));

    /*move ad*/
    cmd = DRV_IOR(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, old_offset, cmd, &ds_ad));
    cmd = DRV_IOW(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, new_offset, cmd, &ds_ad));

    sal_memset(&ds_ad, 0, sizeof(ds_ad));
    cmd = DRV_IOW(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, old_offset, cmd, &ds_ad));

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_l3if_tcam_rtmac_cb(uint8 lchip, uint32 new_offset, uint32 old_offset, void* user_data)
{
    int32 ret = CTC_E_INVALID_PTR;

    ret = _sys_tmm_l3if_tcam_rtmac_move(lchip, new_offset, old_offset);
    if(ret)
    {
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Move index fail when router-mac ofb proccess \n");
        return ret;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_l3if_rtmac_ofb_init(uint8 lchip)
{
    uint32 entry_num = 0;
    uint8 i = 0;
    uint8 ofb_type_rtmac = 0;
    sys_usw_ofb_param_t ofb;
    /*1st index is used for system routermac*/
    entry_num = DRV_TABLE_MAX_INDEX(lchip, DsRouterMacTcamKey_t);

    sal_memset(&ofb, 0, sizeof(sys_usw_ofb_param_t));

    ofb.multiple = 1;
    ofb_type_rtmac = p_usw_l3if_master[lchip]->ofb_type_rtmac;
    CTC_ERROR_RETURN(sys_usw_ofb_init(lchip, SYS_L3IF_OFB_BLK_MAX, entry_num, &ofb_type_rtmac));
    p_usw_l3if_master[lchip]->ofb_type_rtmac = ofb_type_rtmac;
    for(i = 0; i< SYS_L3IF_OFB_BLK_MAX; i++)
    {
        ofb.size = SYS_L3IF_OFB_STEP;
        ofb.ofb_cb = _sys_tmm_l3if_tcam_rtmac_cb;
        CTC_ERROR_RETURN(sys_usw_ofb_init_offset(lchip, p_usw_l3if_master[lchip]->ofb_type_rtmac, i, &ofb));
    }
    /* 0 reserved for global(system) routermac */
    if(CTC_WB_STATUS(lchip) != CTC_WB_STATUS_RELOADING)
    {
        sys_usw_ofb_alloc_offset_from_position(lchip, p_usw_l3if_master[lchip]->ofb_type_rtmac, SYS_L3IF_OFB_BLK_SUB_IF, 0, NULL);
    }
    return CTC_E_NONE;
}

STATIC uint8
_sys_tmm_l3if_rtmac_get_ofb_blk_id(uint8 l3if_type)
{
    uint8 blk_id = 0;
    switch (l3if_type)
    {
        case CTC_L3IF_TYPE_SUB_IF:
            blk_id = SYS_L3IF_OFB_BLK_SUB_IF;
            break;
        case CTC_L3IF_TYPE_SERVICE_IF:
            blk_id = SYS_L3IF_OFB_BLK_SVC_IF;
            break;
        case CTC_L3IF_TYPE_VLAN_IF:
            blk_id = SYS_L3IF_OFB_BLK_VLAN_IF;
            break;
        case CTC_L3IF_TYPE_PHY_IF:
            blk_id = SYS_L3IF_OFB_BLK_PHY_IF;
            break;
        default:
            break;
    }
    return blk_id;
}


STATIC int32
_sys_tmm_l3if_lkup_router_mac(uint8 lchip, sys_l3if_prop_t* p_l3if_prop, mac_addr_t  mac, uint8 *position,sys_tmm_l3if_rtmac_t* p_sw_rtmac_profile)
{
    uint8 loop_i = 0;
    uint8 free_position = 0xFF;

    CTC_PTR_VALID_CHECK(p_l3if_prop);
    CTC_PTR_VALID_CHECK(p_sw_rtmac_profile);

    for (loop_i = 0; loop_i < SYS_L3IF_ROUTER_MAC_NUM_PER_IF; loop_i++)
    {
        if (!CTC_IS_BIT_SET(p_l3if_prop->rtmac_bmp, loop_i))
        {
            if (0xFF == free_position)
            {
                free_position = loop_i;
            }
            continue;
        }
        if (!sal_memcmp(&(p_sw_rtmac_profile[loop_i].mac), mac, sizeof(mac_addr_t)))
        {
            if (position)
            {
                *position = loop_i;
            }
            return CTC_E_EXIST;
        }
    }

    /*not found*/
    if (position)
    {
        *position = free_position;/*0xFF means no resource*/
    }

    return CTC_E_NOT_EXIST;
}

STATIC int32
_sys_tmm_l3if_get_rtmac_from_blk(uint8 lchip,  sys_l3if_prop_t* p_l3if_prop,sys_tmm_l3if_rtmac_t* p_sw_rtmac_profile)
{
    uint32 cmd = 0;
    uint32 hw_mac[2] = {0};
    mac_addr_t sw_mac;
    tbl_entry_t   tcam_key;
    ds_t key;
    ds_t mask;
    ds_t tcam_ad;
    uint16 l3if_id = 0;
    uint16 loop_i = 0;
    uint8  loop_j = 0;
    uint8  is_vartual_mac = 0;
    uint8  find_cnt = 0;
    uint8  find_bmp = 0;

    CTC_PTR_VALID_CHECK(p_sw_rtmac_profile);
    CTC_PTR_VALID_CHECK(p_l3if_prop);

    sal_memset(&key, 0, sizeof(key));
    sal_memset(&mask, 0, sizeof(mask));
    sal_memset(&tcam_ad, 0, sizeof(tcam_ad));
    sal_memset(&sw_mac, 0, sizeof(mac_addr_t));
    tcam_key.data_entry = key;
    tcam_key.mask_entry = mask;

    find_bmp = p_l3if_prop->rtmac_bmp;
    if(!find_bmp)
    {
        return CTC_E_NONE;
    }

    for(loop_i = 1;loop_i < DRV_TABLE_MAX_INDEX(lchip, DsRouterMacTcamKey_t); loop_i++)
    {
        cmd = DRV_IOR(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, loop_i, cmd, &tcam_ad));
        is_vartual_mac = GetDsRouterMacTcamAd(V, isIpv4VirtualMac_f, &tcam_ad) || GetDsRouterMacTcamAd(V, isIpv6VirtualMac_f, &tcam_ad);
        if(!is_vartual_mac)
        {
            continue;
        }
        l3if_id = GetDsRouterMacTcamAd(V, routerMacId_f, &tcam_ad);
        if(p_l3if_prop->l3if_id != l3if_id)
        {
            continue;
        }

        cmd = DRV_IOR(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, loop_i, cmd, &tcam_key));
        GetDsRouterMacTcamKey(A, macDa_f, tcam_key.data_entry, hw_mac);
        SYS_USW_SET_USER_MAC(sw_mac, hw_mac);

        CTC_BIT_FIRST_VALID(find_bmp,SYS_L3IF_ROUTER_MAC_NUM_PER_IF,loop_j);
        sal_memcpy(p_sw_rtmac_profile[loop_j].mac, sw_mac, sizeof(mac_addr_t));
        p_sw_rtmac_profile[loop_j].key_index = loop_i;
        CTC_BIT_UNSET(find_bmp,loop_j);
        find_cnt++;


        if(!find_bmp || SYS_L3IF_ROUTER_MAC_NUM_PER_IF <= find_cnt)
        {
            break;
        }

    }

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_l3if_add_rtmac_to_blk(uint8 lchip,sys_l3if_prop_t *p_l3if_prop, mac_addr_t mac, uint8 position,sys_tmm_l3if_rtmac_t* p_sw_rtmac_profile)
{
    uint32 cmd = 0;
    uint32 key_index = 0;
    hw_mac_addr_t hw_mac;
    tbl_entry_t   tcam_key;
    ds_t key;
    ds_t mask;
    ds_t action;
    uint32 router_mac_id = 0;
    uint8  ofb_type_rtmac = p_usw_l3if_master[lchip]->ofb_type_rtmac;

    CTC_PTR_VALID_CHECK(p_l3if_prop);
    CTC_PTR_VALID_CHECK(p_sw_rtmac_profile);

    sal_memset(hw_mac, 0, sizeof(hw_mac_addr_t));
    sal_memset(key, 0, sizeof(ds_t));
    sal_memset(mask, 0, sizeof(ds_t));
    sal_memset(action, 0, sizeof(ds_t));

    tcam_key.data_entry = key;
    tcam_key.mask_entry = mask;

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_OFB, 1);

    CTC_ERROR_RETURN(sys_usw_ofb_alloc_offset(lchip, ofb_type_rtmac, _sys_tmm_l3if_rtmac_get_ofb_blk_id(p_l3if_prop->l3if_type),
                                                            &key_index,NULL));
    if (CTC_L3IF_TYPE_PHY_IF == p_l3if_prop->l3if_type || CTC_L3IF_TYPE_SUB_IF == p_l3if_prop->l3if_type)
    {
        SetDsRouterMacTcamKey(V, portId_f, &key, SYS_MAP_CTC_GPORT_TO_DRV_GPORT(p_l3if_prop->gport));
        SetDsRouterMacTcamKey(V, portId_f, &mask, 0xFFFF);
    }
    if (CTC_L3IF_TYPE_VLAN_IF == p_l3if_prop->l3if_type || CTC_L3IF_TYPE_SUB_IF == p_l3if_prop->l3if_type)
    {
        SetDsRouterMacTcamKey(V, vlanId_f, &key, p_l3if_prop->vlan_id);
        SetDsRouterMacTcamKey(V, vlanId_f, &mask, 0xFFFF);
    }
    SYS_USW_SET_HW_MAC(hw_mac, mac);
    SetDsRouterMacTcamKey(A, macDa_f, &key, hw_mac);
    sal_memset(hw_mac, 0xFF, sizeof(hw_mac));
    SetDsRouterMacTcamKey(A, macDa_f, &mask, hw_mac);
    SetDsRouterMacTcamAd(V, isIpv4VirtualMac_f, action, 1);
    SetDsRouterMacTcamAd(V, isIpv6VirtualMac_f, action, 1);

    SetDsRouterMacTcamAd(V, routerMacId_f, action, p_l3if_prop->l3if_id);

    cmd = DRV_IOW(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index, cmd, &tcam_key));

    cmd = DRV_IOW(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index, cmd, &action));

    cmd = DRV_IOW(DsSrcInterface_t, DsSrcInterface_routerMacProfile_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, p_l3if_prop->l3if_id, cmd, &router_mac_id));

    sal_memcpy(p_sw_rtmac_profile[position].mac, mac, sizeof(mac_addr_t));
    p_sw_rtmac_profile[position].key_index = key_index;
    CTC_BIT_SET(p_l3if_prop->rtmac_bmp, position);
    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_l3if_del_rtmac_from_blk(uint8 lchip, sys_l3if_prop_t* p_l3if_prop, mac_addr_t mac, uint8 position,sys_tmm_l3if_rtmac_t* p_sw_rtmac_profile)
{
    uint32 cmd = 0;
    tbl_entry_t   tcam_key;
    ds_t key;
    ds_t mask;
    ds_t action;

    CTC_PTR_VALID_CHECK(p_l3if_prop);
    CTC_PTR_VALID_CHECK(p_sw_rtmac_profile);

    sal_memset(&key, 0, sizeof(ds_t));
    sal_memset(&mask, 0, sizeof(ds_t));
    sal_memset(&action, 0, sizeof(ds_t));

    tcam_key.data_entry = key;
    tcam_key.mask_entry = mask;

    cmd = DRV_IOD(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_sw_rtmac_profile[position].key_index, cmd, &tcam_key));

    cmd = DRV_IOW(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_sw_rtmac_profile[position].key_index, cmd, &action));

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_OFB, 1);

    /* free ofb from block */
    CTC_ERROR_RETURN(sys_usw_ofb_free_offset_no_free_data(lchip,  p_usw_l3if_master[lchip]->ofb_type_rtmac,
                                                 _sys_tmm_l3if_rtmac_get_ofb_blk_id(p_l3if_prop->l3if_type), p_sw_rtmac_profile[position].key_index));

    CTC_BIT_UNSET(p_l3if_prop->rtmac_bmp, position);
    sal_memset(p_sw_rtmac_profile[position].mac, 0, sizeof(mac_addr_t));
    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_l3if_set_router_mac_tcam_hw(uint8 lchip, sys_l3if_prop_t* p_l3if_prop, mac_addr_t* mac, uint8 num, uint8 is_add,sys_tmm_l3if_rtmac_t* p_sw_rtmac_profile)
{
    int32 ret = CTC_E_NONE;
    int8 loop = 0;
    uint8 position = 0;

    CTC_PTR_VALID_CHECK(p_l3if_prop);
    CTC_PTR_VALID_CHECK(p_sw_rtmac_profile);
    CTC_PTR_VALID_CHECK(mac);

    for (loop = 0; loop < num; loop++)
    {
        ret = _sys_tmm_l3if_lkup_router_mac(lchip,  p_l3if_prop, mac[loop], &position,p_sw_rtmac_profile);
        if ((is_add) && (CTC_E_NOT_EXIST == ret))   /*add*/
        {
            if (0xFF == position)
            {
                SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [L3if] Over max router mac number per Interface\n");
                ret = CTC_E_NO_RESOURCE;
                goto error0;
            }
            CTC_ERROR_GOTO(_sys_tmm_l3if_add_rtmac_to_blk(lchip,  p_l3if_prop, mac[loop],  position,p_sw_rtmac_profile),ret,error0);
        }
        else if ((!is_add) && (CTC_E_EXIST == ret))  /*delete*/
        {
            CTC_ERROR_RETURN(_sys_tmm_l3if_del_rtmac_from_blk(lchip, p_l3if_prop, mac[loop], position,p_sw_rtmac_profile));
        }
        else
        {
            continue;
        }
    }
    return CTC_E_NONE;
error0:
    for (loop -= 1; loop >= 0; loop--)/*Add fail rollback,delete previous add*/
    {
        int32 ret_lookup = 0;
        ret_lookup = _sys_tmm_l3if_lkup_router_mac(lchip,  p_l3if_prop, mac[loop], &position,p_sw_rtmac_profile);
        if (CTC_E_EXIST == ret_lookup)
        {
            SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [L3if] Add Not complete,delete previous entry \n");
            CTC_ERROR_RETURN(_sys_tmm_l3if_del_rtmac_from_blk(lchip, p_l3if_prop, mac[loop], position,p_sw_rtmac_profile));
        }
    }
    return ret;

}


STATIC int32
_sys_tmm_l3if_rmac_fpa_block_init(uint8 lchip)
{
    uint32 size = 0;
    uint32 ltb_size = 0;
    ctc_fpa_block_t *p_rmac_fpab = NULL;
    sys_l3if_rmac_block_t *p_rmac = NULL;

    ltb_size = DRV_TABLE_MAX_INDEX(lchip, DsRouterMacTcamKey_t);

    size = sizeof(sys_l3if_rmac_entry_t*) * ltb_size;
    p_rmac = p_tmm_l3if_rmac_entry_master[lchip]->rmac_block;
    sal_memset(p_rmac, 0, sizeof(sys_l3if_rmac_block_t));
    p_rmac_fpab = &p_rmac->fpab;
    MALLOC_ZERO(MEM_L3IF_MODULE, p_rmac_fpab->entries, size);
    if ((NULL == p_rmac_fpab->entries) && (size != 0))
    {
        CTC_ERROR_RETURN(CTC_E_NO_MEMORY);
    }

    p_rmac_fpab->entry_count = ltb_size - 1;
    p_rmac_fpab->free_count = ltb_size - 1;
    p_rmac_fpab->start_offset[0] = 1;
    p_rmac_fpab->sub_entry_count[0] = ltb_size - 1;
    p_rmac_fpab->sub_free_count[0] = ltb_size - 1;
    p_rmac_fpab->sub_rsv_count[0] = 0;
    p_rmac_fpab->part_num = 1;

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_l3if_get_rmac_block_by_pe_fpa(uint8 lchip, ctc_fpa_entry_t* pe, ctc_fpa_block_t** pb)
{
    sys_l3if_rmac_block_t *rmac_block = NULL;

    CTC_PTR_VALID_CHECK(pe);
    CTC_PTR_VALID_CHECK(pb);

    *pb = NULL;

    rmac_block = p_tmm_l3if_rmac_entry_master[lchip]->rmac_block;

    *pb = &(rmac_block->fpab);

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_l3if_rmac_move_hw_fpa(uint8 lchip, ctc_fpa_entry_t* p_fpa_entry, int32 tcam_idx_new)
{
    uint32  tcam_idx_old = 0;
    uint32  cmd = 0;
    ds_t key, mask;
    ds_t action;
    tbl_entry_t tcam_key;
    sys_l3if_rmac_entry_t* rmac_entry = NULL;

    CTC_PTR_VALID_CHECK(p_fpa_entry);

    sal_memset(&key, 0, sizeof(key));
    sal_memset(&mask, 0, sizeof(mask));
    sal_memset(&action, 0, sizeof(action));

    if (p_fpa_entry->flag != FPA_ENTRY_FLAG_INSTALLED)
    {
        return CTC_E_NONE;
    }

    /*get entry*/
    rmac_entry = ctc_hash_lookup(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, p_fpa_entry);

    if (NULL == rmac_entry)
    {
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [L3if] Entry not exist \n");
        return CTC_E_NOT_EXIST;
    }

    tcam_idx_old = rmac_entry->fpae.offset_a;
    /*1. get old key from hw*/
    cmd = DRV_IOR(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    tcam_key.data_entry = key;
    tcam_key.mask_entry = mask;
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, tcam_idx_old, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &tcam_key));
    /*2. get old action from hw*/
    cmd = DRV_IOR(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, tcam_idx_old, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &action));
    /*3. move old action to new ad index*/
    cmd = DRV_IOW(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, tcam_idx_new, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &action));
    /*4. move old key to new ad index*/
    cmd = DRV_IOW(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    tcam_key.data_entry = key;
    tcam_key.mask_entry = mask;
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, tcam_idx_new, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &tcam_key));
    /*5. delete old key*/
    cmd = DRV_IOD(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, tcam_idx_old, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &cmd));
    /* set new_index */
    p_fpa_entry->offset_a = tcam_idx_new;

    return CTC_E_NONE;
}

int32
_sys_tmm_l3if_install_router_mac_entry(uint8 lchip, uint32 key_index, ctc_l3if_rmac_entry_t* rmac_entry)
{
    uint32  cmd = 0;
    uint32  hw_mac[2] = {0};
    uint16  lport = 0;
    uint16  lport_mask = 0;
    tbl_entry_t   tcam_key;
    ds_t key, mask;
    ds_t action;

    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&key, 0, sizeof(key));
    sal_memset(&mask, 0, sizeof(mask));
    sal_memset(&action, 0, sizeof(action));
    sal_memset(&tcam_key, 0, sizeof(tcam_key));

    tcam_key.data_entry = key;
    tcam_key.mask_entry = mask;

    lport = SYS_MAP_CTC_GPORT_TO_DRV_GPORT(rmac_entry->gport);
    lport_mask = SYS_MAP_CTC_GPORT_TO_DRV_GPORT(rmac_entry->gport_mask);

    SYS_USW_SET_HW_MAC(hw_mac, rmac_entry->mac);
    SetDsRouterMacTcamKey(A, macDa_f, &key, hw_mac);
    SYS_USW_SET_HW_MAC(hw_mac, rmac_entry->mac_mask);
    SetDsRouterMacTcamKey(A, macDa_f, &mask, hw_mac);
    SetDsRouterMacTcamKey(V, vlanId_f, &key, rmac_entry->vlan_id);
    SetDsRouterMacTcamKey(V, vlanId_f, &mask, rmac_entry->vlan_id_mask);
    SetDsRouterMacTcamKey(V, portId_f, &key, lport);
    SetDsRouterMacTcamKey(V, portId_f, &mask, lport_mask);
    cmd = DRV_IOW(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &tcam_key));

    if (CTC_FLAG_ISSET (rmac_entry->flag, CTC_L3IF_RMAC_ENTRY_RMAC_ID))
    {
        SetDsRouterMacTcamAd(V, routerMacId_f, &action, rmac_entry->rmac_id);
        SetDsRouterMacTcamAd(V, isRouterMac_f, &action, 0);
    }
    else if (CTC_FLAG_ISSET (rmac_entry->flag, CTC_L3IF_RMAC_ENTRY_BIND_L3IF))
    {
        SetDsRouterMacTcamAd(V, isIpv4VirtualMac_f, &action, 1);
        SetDsRouterMacTcamAd(V, isIpv6VirtualMac_f, &action, 1);
        SetDsRouterMacTcamAd(V, isVirtualMac_f, &action, 1);
        SetDsRouterMacTcamAd(V, routerMacId_f, &action, rmac_entry->rmac_id);
        SetDsRouterMacTcamAd(V, isRouterMac_f, &action, 0);
    }
    else
    {
        SetDsRouterMacTcamAd(V, routerMacId_f, &action, 0);
        SetDsRouterMacTcamAd(V, isRouterMac_f, &action, 1);
    }
    
    cmd = DRV_IOW(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &action));

    return CTC_E_NONE;
}

int32
_sys_tmm_l3if_wb_traverse_sync_route_mac(sys_l3if_rmac_entry_t* p_rtmac_entry, void *user_data)
{
    ctc_wb_data_t *wb_data = (ctc_wb_data_t*)user_data;
    sys_wb_l3if_router_mac_entry_t  *p_l3if_wb_router_mac;

    p_l3if_wb_router_mac = (sys_wb_l3if_router_mac_entry_t *)wb_data->buffer + wb_data->valid_cnt;

    p_l3if_wb_router_mac->entry_id = p_rtmac_entry->fpae.entry_id;
    p_l3if_wb_router_mac->fpa_offset_a = p_rtmac_entry->fpae.offset_a;
    p_l3if_wb_router_mac->priority = p_rtmac_entry->fpae.priority;
    p_l3if_wb_router_mac->rsv = 0;
    wb_data->valid_cnt++;

    return CTC_E_NONE;
}

int32
_sys_tmm_l3if_dump_rtmac_entry(sys_l3if_rmac_entry_t *p_rtmac_entry, void *user_data)
{
    sal_file_t dump_db_fp = ((sys_dump_db_traverse_param_t*)user_data)->value0;
    uint32* cnt = (uint32*)((sys_dump_db_traverse_param_t*)user_data)->value1;
    SYS_DUMP_DB_LOG(dump_db_fp, "%-5d%-10d%-5d%-11d\n", *cnt, p_rtmac_entry->fpae.entry_id, p_rtmac_entry->fpae.priority, p_rtmac_entry->fpae.offset_a);
    (*cnt)++;
    return CTC_E_NONE;
}

STATIC int32
_sys_at_l3if_rtmac_pp_hash_init(uint8 lchip)
{
    uint8 pp_num = SYS_PP_NUM(lchip);
    uint32 entry_num = 0;
    uint32 block_size = 0;
    entry_num = (DRV_TABLE_MAX_INDEX(lchip, DsRouterMacTcamKey_t)*pp_num);
    block_size = CTC_HASH_32_BLOCK_SIZE;
    p_usw_l3if_master[lchip]->rmac_pp_hash = sys_usw_com_entry_hash_init(lchip, entry_num, block_size);

    if(!p_usw_l3if_master[lchip]->rmac_pp_hash)
    {
        return CTC_E_NO_MEMORY;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_tmm_l3if_wb_init(uint8 lchip)
{
    ctc_wb_appid_t  appid;
    sal_memset(&appid,0,sizeof(appid));

    if(p_usw_l3if_master[lchip]->rtmac_mode)
    {
        appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_ROUTER_MAC_ENTRY) ;
        appid.entry_num = MCHIP_CAP(SYS_CAP_L3IF_ROUTER_MAC_NUM);
        appid.entry_size  = sizeof(sys_wb_l3if_router_mac_entry_t);
        appid.rt_en = 0;
        ctc_wb_add_appid(lchip, &appid);
    }
    else if(!SYS_VCHIP_PP_IS_NOT_BASE(lchip))
    {
        appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_OFB) ;
        appid.entry_num = DRV_TABLE_MAX_INDEX(lchip, DsRouterMacTcamKey_t);
        appid.entry_size  = sizeof(sys_wb_ofb_t);
        appid.rt_en = 0;
        ctc_wb_add_appid(lchip, &appid);
    }

    return CTC_E_NONE;
}

int32
sys_tmm_l3if_set_igs_if_rmac(uint8 lchip, uint16 l3if_id, ctc_l3if_router_mac_t router_mac)
{
    int32 ret = CTC_E_NONE;
    uint8 loop_i = 0;
    uint8 loop_j = 0;
    uint8 is_add = 0;
    uint8 rollback_num = 0;
    mac_addr_t  old_mac[SYS_L3IF_ROUTER_MAC_NUM_PER_IF];
    sys_l3if_prop_t* p_l3if_prop = NULL;
    sys_tmm_l3if_rtmac_t sw_rtmac_profile[SYS_L3IF_ROUTER_MAC_NUM_PER_IF];

    sal_memset(old_mac, 0, sizeof(mac_addr_t)*SYS_L3IF_ROUTER_MAC_NUM_PER_IF);
    SYS_L3IF_INIT_CHECK();
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    lchip = SYS_PP_BASE(lchip);
    p_l3if_prop = &p_usw_l3if_master[lchip]->l3if_prop[l3if_id];
    if(!p_l3if_prop->valid)
    {
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [L3if] Not exist! \n");\
        return CTC_E_NOT_EXIST;
    }

    sal_memset(sw_rtmac_profile, 0, sizeof(sw_rtmac_profile));
    CTC_ERROR_RETURN(_sys_tmm_l3if_get_rtmac_from_blk(lchip ,p_l3if_prop,sw_rtmac_profile));

    if (CTC_L3IF_APPEND_ROUTE_MAC == router_mac.mode)
    {
        is_add = 1;
        CTC_ERROR_GOTO(_sys_tmm_l3if_set_router_mac_tcam_hw(lchip, p_l3if_prop, router_mac.mac, router_mac.num, is_add, sw_rtmac_profile), ret , End);
    }
    else if(CTC_L3IF_DELETE_ROUTE_MAC == router_mac.mode)
    {
        is_add = 0;
        CTC_ERROR_GOTO(_sys_tmm_l3if_set_router_mac_tcam_hw(lchip, p_l3if_prop, router_mac.mac, router_mac.num, is_add, sw_rtmac_profile), ret , End);
    }
    else /* CTC_L3IF_UPDATE_ROUTE_MAC: lkup routermacs which need to append, and lkup routermacs which need to remove */
    {
        mac_addr_t  mac[SYS_L3IF_ROUTER_MAC_NUM_PER_IF];
        uint8 num = 0;
        sal_memset(mac, 0, sizeof(mac_addr_t)*SYS_L3IF_ROUTER_MAC_NUM_PER_IF);

        for (loop_i = 0; loop_i< SYS_L3IF_ROUTER_MAC_NUM_PER_IF;loop_i++)  /* delete */
        {
            if (!CTC_IS_BIT_SET(p_l3if_prop->rtmac_bmp, loop_i))
            {
                continue;
            }
            for (loop_j = 0; loop_j < router_mac.num; loop_j++)
            {
                if (!sal_memcmp(sw_rtmac_profile[loop_i].mac, &router_mac.mac[loop_j], sizeof(mac_addr_t)))
                {
                    break;
                }
            }
            if(loop_j == router_mac.num)/*old mac[loop_i] NOT exist in new mac*/
            {
                sal_memcpy(&mac[num], sw_rtmac_profile[loop_i].mac, sizeof(mac_addr_t));
                sal_memcpy(&old_mac[num++], sw_rtmac_profile[loop_i].mac, sizeof(mac_addr_t));
            }
        }
        rollback_num = num;
        is_add = 0;
        CTC_ERROR_GOTO(_sys_tmm_l3if_set_router_mac_tcam_hw(lchip, p_l3if_prop, mac, num, is_add,sw_rtmac_profile), ret , error0);

        num = 0;
        for (loop_i = 0; loop_i < router_mac.num; loop_i++)            /* add */
        {
            ret = _sys_tmm_l3if_lkup_router_mac(lchip,  p_l3if_prop, router_mac.mac[loop_i], NULL,sw_rtmac_profile);
            if(CTC_E_NOT_EXIST == ret)
            {
                sal_memcpy(&mac[num++], &(router_mac.mac[loop_i]), sizeof(mac_addr_t));
            }
        }
        is_add = 1;
        CTC_ERROR_GOTO(_sys_tmm_l3if_set_router_mac_tcam_hw(lchip, p_l3if_prop, mac, num, is_add,sw_rtmac_profile), ret , error0);
    }

error0:
    if(CTC_E_NONE != ret)
    {
        is_add = 1;/*Update fail rollback,add old mac back */
        CTC_ERROR_DUMP(_sys_tmm_l3if_set_router_mac_tcam_hw(lchip, p_l3if_prop, old_mac, rollback_num, is_add,sw_rtmac_profile));
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [L3if] Rollback origin %d router mac \n",rollback_num);
    }

End:
    return ret;
}

int32
sys_tmm_l3if_get_igs_if_rmac(uint8 lchip, uint16 l3if_id, ctc_l3if_router_mac_t* router_mac)
{
	uint8   rtmac_bmp;
    uint8   i = 0, k = 0;
    uint32  query_index = 0;
    sys_tmm_l3if_rtmac_t sw_rtmac_profile[SYS_L3IF_ROUTER_MAC_NUM_PER_IF];
    sys_l3if_prop_t* p_l3if_prop = NULL;

    SYS_L3IF_INIT_CHECK();
    SYS_L3IFID_VAILD_CHECK(l3if_id);
    CTC_PTR_VALID_CHECK(router_mac);

    p_l3if_prop = &p_usw_l3if_master[lchip]->l3if_prop[l3if_id];
	if(!p_l3if_prop->valid)
    {
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [L3if] Not exist! \n");
        return CTC_E_NOT_EXIST;
    }
    rtmac_bmp = p_l3if_prop->rtmac_bmp;
    sal_memset(sw_rtmac_profile, 0, sizeof(sw_rtmac_profile));
    CTC_ERROR_RETURN(_sys_tmm_l3if_get_rtmac_from_blk(lchip ,p_l3if_prop,sw_rtmac_profile));

    for (i = 0; i < SYS_L3IF_ROUTER_MAC_NUM_PER_IF; i++)
    {
        if (!CTC_IS_BIT_SET(rtmac_bmp, i))
        {
            continue;
        }
        if (query_index++ < router_mac->next_query_index)
        {
            continue;
        }
        sal_memcpy(router_mac->mac[k], sw_rtmac_profile[i].mac, sizeof(mac_addr_t));
        router_mac->num++;
        if (++k == MAX_ROUTER_MAC_NUM_PER_ENTRY)
        {
            router_mac->next_query_index = query_index;
            return CTC_E_NONE;
        }
    }
    return CTC_E_NONE;
}

int32
sys_tmm_l3if_set_system_router_mac(uint8 lchip, mac_addr_t mac_addr)
{
    uint32  cmd = 0;
    uint32  hw_mac[2] = {0};
    mac_addr_t usr_mac;
    tbl_entry_t   tcam_key;
    ds_t key;
    ds_t mask;
    ds_t action;

    SYS_L3IF_INIT_CHECK();
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(usr_mac, 0, sizeof(mac_addr_t));
    sal_memset(&tcam_key, 0, sizeof(tcam_key));
    sal_memset(key, 0, sizeof(ds_t));
    sal_memset(mask, 0, sizeof(ds_t));
    sal_memset(action, 0, sizeof(ds_t));
    tcam_key.data_entry = key;
    tcam_key.mask_entry = mask;

    if (!sal_memcmp(hw_mac, mac_addr, sizeof(mac_addr_t)))
    {
        cmd = DRV_IOW(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_SYSTEM_RTMAC_INDEX, cmd, &tcam_key));
        cmd = DRV_IOW(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_SYSTEM_RTMAC_INDEX, cmd, &action));
    }

    SYS_USW_SET_HW_MAC(hw_mac, mac_addr);
    SetDsRouterMacTcamKey(A, macDa_f, &key, hw_mac);
    sal_memset(hw_mac, 0xFF, sizeof(hw_mac));
    SetDsRouterMacTcamKey(A, macDa_f, &mask, hw_mac);
    cmd = DRV_IOW(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_SYSTEM_RTMAC_INDEX, cmd, &tcam_key));
    SetDsRouterMacTcamAd(V, isRouterMac_f, &action, 1);
    cmd = DRV_IOW(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, SYS_SYSTEM_RTMAC_INDEX, cmd, &action));

    return CTC_E_NONE;
}

int32
sys_tmm_l3if_add_router_mac_entry(uint8 lchip, uint32 entry_id, ctc_l3if_rmac_entry_t* rmac_entry)
{
    uint32  key_index = 0;
    uint8 gchip = 0;
	int32 ret = CTC_E_NONE;
    sys_l3if_rmac_block_t *rmac_block = NULL;
    sys_l3if_rmac_entry_t *p_rmac_entry = NULL;
    sys_l3if_rmac_entry_t rmac_entry_temp;

    SYS_L3IF_INIT_CHECK();
    if (!p_tmm_l3if_rmac_entry_master[lchip])
    {
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Feature not initialized \n");
        return CTC_E_NOT_INIT;
    }
    CTC_PTR_VALID_CHECK(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash);
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&rmac_entry_temp, 0, sizeof(rmac_entry_temp));

    if (rmac_entry->vlan_id_mask)
    {
       CTC_MAX_VALUE_CHECK(rmac_entry->vlan_id,CTC_MAX_VLAN_ID);
    }
    if (rmac_entry->gport_mask)
    {
        SYS_GLOBAL_PORT_CHECK(rmac_entry->gport);
        gchip = SYS_MAP_CTC_GPORT_TO_GCHIP(rmac_entry->gport);
        if (SYS_GCHIP_IS_REMOTE(lchip, gchip))
        {
            return CTC_E_INVALID_PARAM;
        }
    }

    if (CTC_FLAG_ISSET (rmac_entry->flag, CTC_L3IF_RMAC_ENTRY_BIND_L3IF))
    {
        SYS_L3IFID_VAILD_CHECK(rmac_entry->rmac_id);
    }
    else if (CTC_FLAG_ISSET (rmac_entry->flag, CTC_L3IF_RMAC_ENTRY_RMAC_ID) && (rmac_entry->rmac_id > SYS_L3IF_MAX_ROUTER_MAC_ID))
    {
        return CTC_E_INVALID_PARAM;
    }

    rmac_entry_temp.fpae.entry_id = entry_id;
    p_rmac_entry = ctc_hash_lookup(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, &rmac_entry_temp);
    if (NULL != p_rmac_entry)
    {
        rmac_entry_temp.fpae.priority = rmac_entry->priority ? rmac_entry->priority : 1;
        if (p_rmac_entry->fpae.priority != rmac_entry_temp.fpae.priority)
        {
            return CTC_E_NOT_SUPPORT;
        }
        ret = _sys_tmm_l3if_install_router_mac_entry(lchip, p_rmac_entry->fpae.offset_a, rmac_entry);
        return ret;
    }

    p_rmac_entry = mem_malloc(MEM_L3IF_MODULE, sizeof(sys_l3if_rmac_entry_t));
    if (NULL == p_rmac_entry)
    {
        return CTC_E_NO_MEMORY;
    }

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_ROUTER_MAC_ENTRY, 1);
    p_rmac_entry->fpae.entry_id = entry_id;
    if (NULL == ctc_hash_insert(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, p_rmac_entry))
    {
        ret = CTC_E_NO_RESOURCE;
        goto error0;
    }

    if (rmac_entry->priority)
    {
        p_rmac_entry->fpae.priority = rmac_entry->priority;
    }
    else
    {
        p_rmac_entry->fpae.priority = 1;  /* default priority */
    }

    /* alloc block index. */
    rmac_block = p_tmm_l3if_rmac_entry_master[lchip]->rmac_block;
    CTC_ERROR_GOTO(fpa_usw_alloc_offset(p_tmm_l3if_rmac_entry_master[lchip]->rmac_fpa, &rmac_block->fpab, 0, rmac_entry->priority, &key_index), ret, error1);
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Add route mac key index: %d\n", key_index);
    /* add to block */
    rmac_block->fpab.entries[key_index] = &p_rmac_entry->fpae;

    p_rmac_entry->fpae.offset_a = key_index;
    p_rmac_entry->fpae.step = 1;
    p_rmac_entry->fpae.real_step = 1;
    p_rmac_entry->fpae.flag = FPA_ENTRY_FLAG_UNINSTALLED;
    p_rmac_entry->fpae.entry_id = entry_id;
    p_rmac_entry->fpae.key_size = 0;

    /* install rmac entry */
    CTC_ERROR_GOTO(_sys_tmm_l3if_install_router_mac_entry(lchip, key_index, rmac_entry), ret, error2);

    p_rmac_entry->fpae.flag = FPA_ENTRY_FLAG_INSTALLED;

    return ret;

    error2:
        fpa_usw_free_offset(&rmac_block->fpab, key_index);
    error1:
        ctc_hash_remove(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, p_rmac_entry);
    error0:
        if (p_rmac_entry)
        {
            mem_free(p_rmac_entry);
        }
        return ret;
}

int32
sys_tmm_l3if_remove_router_mac_entry(uint8 lchip, uint32 entry_id)
{
    uint32  key_index = 0;
    uint32  cmd = 0;
    sys_l3if_rmac_block_t *rmac_block = NULL;
    sys_l3if_rmac_entry_t *p_rmac_entry = NULL;
    sys_l3if_rmac_entry_t rmac_entry_temp;

    SYS_L3IF_INIT_CHECK();
    if (!p_tmm_l3if_rmac_entry_master[lchip])
    {
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Feature not initialized \n");
        return CTC_E_NOT_INIT;
    }
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&rmac_entry_temp, 0, sizeof(rmac_entry_temp));
    rmac_entry_temp.fpae.entry_id = entry_id;

    p_rmac_entry = ctc_hash_lookup(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, &rmac_entry_temp);
    if (NULL == p_rmac_entry)
    {
        return CTC_E_ENTRY_NOT_EXIST;
    }

    key_index = p_rmac_entry->fpae.offset_a;

    rmac_block = p_tmm_l3if_rmac_entry_master[lchip]->rmac_block;
    CTC_ERROR_RETURN(fpa_usw_free_offset(&rmac_block->fpab, key_index));
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Remove route mac key index: %d\n", key_index);

    cmd = DRV_IOD(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, key_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &cmd));

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_ROUTER_MAC_ENTRY, 1);

    p_rmac_entry = ctc_hash_remove(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, &rmac_entry_temp);
    if (p_rmac_entry)
    {
        mem_free(p_rmac_entry);
    }
    return CTC_E_NONE;
}

int32
sys_tmm_l3if_get_router_mac_entry(uint8 lchip, uint32 entry_id, ctc_l3if_rmac_entry_t* rmac_entry)
{
    sys_l3if_rmac_entry_t *p_rmac_entry = NULL;
    sys_l3if_rmac_entry_t rmac_entry_temp;
    uint16 lport = 0;
    uint8 field_val = 0;
    uint32 cmd;
    uint32  hw_mac[2] = {0};
    mac_addr_t mac_addr;
    tbl_entry_t  tcam_key;
    ds_t key, mask;
    ds_t action;

    SYS_L3IF_INIT_CHECK();
    if (!p_tmm_l3if_rmac_entry_master[lchip])
    {
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Feature not initialized \n");
        return CTC_E_NOT_INIT;
    }
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&key, 0, sizeof(key));
    sal_memset(&mask, 0, sizeof(mask));
    sal_memset(&action, 0, sizeof(action));
    sal_memset(&mac_addr, 0, sizeof(mac_addr_t));
    sal_memset(&rmac_entry_temp, 0, sizeof(rmac_entry_temp));

    rmac_entry_temp.fpae.entry_id = entry_id;
    tcam_key.data_entry = key;
    tcam_key.mask_entry = mask;

    p_rmac_entry = ctc_hash_lookup(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, &rmac_entry_temp);
    if (NULL == p_rmac_entry)
    {
        return CTC_E_ENTRY_NOT_EXIST;
    }

    cmd = DRV_IOR(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_rmac_entry->fpae.offset_a, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &tcam_key));

    GetDsRouterMacTcamKey(A, macDa_f, tcam_key.data_entry, hw_mac);
    SYS_USW_SET_USER_MAC(rmac_entry->mac, hw_mac);
    GetDsRouterMacTcamKey(A, macDa_f, tcam_key.mask_entry, hw_mac);
    SYS_USW_SET_USER_MAC(rmac_entry->mac_mask, hw_mac);

    lport = GetDsRouterMacTcamKey(V, portId_f, tcam_key.data_entry);
    rmac_entry->gport = SYS_MAP_DRV_GPORT_TO_CTC_GPORT(lport);
    lport = GetDsRouterMacTcamKey(V, portId_f, tcam_key.mask_entry);
    rmac_entry->gport_mask = SYS_MAP_DRV_GPORT_TO_CTC_GPORT(lport);

    rmac_entry->vlan_id = GetDsRouterMacTcamKey(V, vlanId_f, tcam_key.data_entry);
    rmac_entry->vlan_id_mask = GetDsRouterMacTcamKey(V, vlanId_f, tcam_key.mask_entry);

    rmac_entry->priority = p_rmac_entry->fpae.priority;

    cmd = DRV_IOR(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_rmac_entry->fpae.offset_a, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_L3IF)), &action));
    rmac_entry->rmac_id = GetDsRouterMacTcamAd(V, routerMacId_f, &action);
    field_val = GetDsRouterMacTcamAd(V, isVirtualMac_f, &action);
    if (field_val)
    {
        CTC_SET_FLAG(rmac_entry->flag, CTC_L3IF_RMAC_ENTRY_BIND_L3IF);
    }
    else
    {
        field_val = GetDsRouterMacTcamAd(V, isRouterMac_f, &action);
        if(!field_val)
        {
            CTC_SET_FLAG(rmac_entry->flag, CTC_L3IF_RMAC_ENTRY_RMAC_ID);
        }
    }

    return CTC_E_NONE;
}

int32
sys_tmm_l3if_show_router_mac_entry(uint8 lchip, uint32 entry_id)
{
    sys_l3if_rmac_entry_t *p_rmac_entry = NULL;
    sys_l3if_rmac_entry_t rmac_entry_temp;
    tbl_entry_t  tcam_key;
    ds_t key, mask;
    ds_t action;

    SYS_L3IF_INIT_CHECK();
    if (!p_tmm_l3if_rmac_entry_master[lchip])
    {
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Feature not initialized \n");
        return CTC_E_NOT_INIT;
    }
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&key, 0, sizeof(key));
    sal_memset(&mask, 0, sizeof(mask));
    sal_memset(&action, 0, sizeof(action));
    sal_memset(&rmac_entry_temp, 0, sizeof(rmac_entry_temp));
    sal_memset(&tcam_key, 0, sizeof(tbl_entry_t));

    if (DRV_FROM_TMM(lchip))
    {
        rmac_entry_temp.fpae.entry_id = entry_id;
        tcam_key.data_entry = key;
        tcam_key.mask_entry = mask;

        p_rmac_entry = ctc_hash_lookup(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, &rmac_entry_temp);
        if (NULL == p_rmac_entry)
        {
            return CTC_E_ENTRY_NOT_EXIST;
        }

        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "#ENTRY_ID: %-12u", entry_id);
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Table:\n");
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --DsRouterMacTcamKey        : %d\n", p_rmac_entry->fpae.offset_a);
        SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --DsRouterMacTcamAd         : %d\n", p_rmac_entry->fpae.offset_a);
    }

    return CTC_E_NONE;
}

int32
sys_tmm_l3if_db_init(uint8 lchip, uint8 deinit)
{
    int32 ret = CTC_E_NONE;

    SYS_L3IF_INIT_CHECK();
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    if (deinit)
    {
        if(p_tmm_l3if_rmac_entry_master[lchip])
        {
            SYS_VCHIP_MASTER_DEINIT(lchip, p_tmm_l3if_rmac_entry_master, CTC_FEATURE_L3IF); 

            if (DRV_IS_AT(lchip) && MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_L3IF) && !SYS_VCHIP_PP_IS_NOT_BASE(lchip))
            {
                sys_usw_com_entry_hash_deinit(lchip, p_usw_l3if_master[lchip]->rmac_pp_hash);/*use ctc_hash_free2*/
            }
            if(p_tmm_l3if_rmac_entry_master[lchip]->rmac_block->fpab.entries)
            {
                mem_free(p_tmm_l3if_rmac_entry_master[lchip]->rmac_block->fpab.entries);
            }
            mem_free(p_tmm_l3if_rmac_entry_master[lchip]->rmac_block);
            fpa_usw_free(p_tmm_l3if_rmac_entry_master[lchip]->rmac_fpa);
            ctc_hash_traverse(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, (hash_traversal_fn)sys_usw_l3if_free_node_data, NULL);
            ctc_hash_free(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash);
            mem_free(p_tmm_l3if_rmac_entry_master[lchip]);
        }
        else
        {
            if (SYS_VCHIP_PP_IS_NOT_BASE(lchip))
            { 
                return CTC_E_NONE;
            }
            sys_usw_ofb_deinit(lchip, p_usw_l3if_master[lchip]->ofb_type_rtmac, 1);
            p_usw_l3if_master[lchip]->ofb_type_rtmac = 0;
        }
        return ret;
    }

    if (p_usw_l3if_master[lchip]->rtmac_mode)
    {
        if (NULL != p_tmm_l3if_rmac_entry_master[lchip])
        {
            return CTC_E_NONE;
        }
        SYS_VCHIP_MASTER_INIT(lchip, p_tmm_l3if_rmac_entry_master, CTC_FEATURE_L3IF);

        if (DRV_IS_AT(lchip) && MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_L3IF) && !SYS_VCHIP_PP_IS_NOT_BASE(lchip))
        {
            CTC_ERROR_RETURN(_sys_at_l3if_rtmac_pp_hash_init(lchip));
        }

        MALLOC_ZERO(MEM_L3IF_MODULE, p_tmm_l3if_rmac_entry_master[lchip], sizeof(sys_l3if_rmac_entry_master_t));
        if (NULL == p_tmm_l3if_rmac_entry_master[lchip])
        {
            return CTC_E_NO_MEMORY;
        }

        p_tmm_l3if_rmac_entry_master[lchip]->rmac_block = mem_malloc(MEM_L3IF_MODULE, sizeof(sys_l3if_rmac_block_t));
        if (NULL == p_tmm_l3if_rmac_entry_master[lchip]->rmac_block)
        {
            SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "No Memory\n");
            ret = CTC_E_NO_MEMORY;
            goto error0;
        }

        p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash  = ctc_hash_create((DRV_TABLE_MAX_INDEX(lchip, DsRouterMacTcamKey_t) / CTC_HASH_32_BLOCK_SIZE
                                                            / SYS_HASH_SIZE_COMPRESS_RATE_4),CTC_HASH_32_BLOCK_SIZE,
                                                            (hash_key_fn)_sys_usw_l3if_rmac_hash_make,
                                                            (hash_cmp_fn)_sys_usw_l3if_rmac_hash_cmp);

        if (NULL == p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash)
        {
            SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "No Memory\n");
            ret = CTC_E_NO_MEMORY;
            goto error0;
        }

        p_tmm_l3if_rmac_entry_master[lchip]->rmac_fpa = fpa_usw_create(lchip,
                                                                       _sys_tmm_l3if_get_rmac_block_by_pe_fpa,
                                                                       _sys_tmm_l3if_rmac_move_hw_fpa,
                                                                       0);
        if (NULL == p_tmm_l3if_rmac_entry_master[lchip]->rmac_fpa)
        {
            SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "No Memory\n");
            ret = CTC_E_NO_MEMORY;
            goto error0;
        }
        CTC_ERROR_GOTO(_sys_tmm_l3if_rmac_fpa_block_init(lchip), ret, error0);
    }
    else
    {
        if(!p_usw_l3if_master[lchip]->ofb_type_rtmac)
        {
            /*init routermac ofb to manage DsRoutermacTcam index*/
            CTC_ERROR_GOTO(_sys_tmm_l3if_rtmac_ofb_init(lchip),ret,error0);
        } 
    }

    if (CTC_WB_ENABLE(lchip))
    {
        _sys_tmm_l3if_wb_init(lchip);
    }

    return ret;

error0:
    if (p_usw_l3if_master[lchip]->rtmac_mode)
    {
        if (p_tmm_l3if_rmac_entry_master[lchip]->rmac_fpa)
        {
            fpa_usw_free(p_tmm_l3if_rmac_entry_master[lchip]->rmac_fpa);
        }

        if (p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash)
        {
            ctc_hash_free(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash);
        }

        if (p_tmm_l3if_rmac_entry_master[lchip]->rmac_block)
        {
            mem_free(p_tmm_l3if_rmac_entry_master[lchip]->rmac_block);
        }

        if (p_tmm_l3if_rmac_entry_master[lchip])
        {
            mem_free(p_tmm_l3if_rmac_entry_master[lchip]);
        }
    }
    else
    {
        sys_usw_ofb_deinit(lchip, p_usw_l3if_master[lchip]->ofb_type_rtmac, 1);
        p_usw_l3if_master[lchip]->ofb_type_rtmac = 0;
    }
    return ret;
}


int32
sys_tmm_l3if_wb_rtmac_restore(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    uint16 i = 0;
    uint16 l3if_id = 0;
    uint32 cmd = 0;
    uint32 field_val = 0;
    uint32  mac[2] ={0};
    uint32 entry_cnt = 0;
    mac_addr_t mac_addr;
    mac_addr_t mac_addr_cmp;
    tbl_entry_t         tcam_key;
    ds_t         tcam_ad;
    sys_l3if_prop_t* p_l3if_prop = NULL;
    sys_l3if_macinner_profile_t egs_profile;
    sys_l3if_macinner_profile_t *p_egs_get_profile = NULL;
    sys_wb_l3if_router_mac_entry_t wb_rtmac;
    ds_t tcamkey, tcammask;
    ctc_wb_query_t wb_query;
    sys_l3if_rmac_entry_t *p_rtmac_entry = NULL;
    DsEgressRouterMac_m  egs_router_mac;


    sal_memset(&mac_addr, 0, sizeof(mac_addr_t));
    sal_memset(&mac_addr_cmp, 0, sizeof(mac_addr_t));
    sal_memset(&tcamkey, 0, sizeof(ds_t));
    sal_memset(&tcammask, 0, sizeof(ds_t));
    tcam_key.data_entry = (uint32*)&tcamkey;
    tcam_key.mask_entry = (uint32*)&tcammask;

    /* restore egress router mac */
    if(!SYS_VCHIP_PP_IS_NOT_BASE(lchip))
    {
        for (i = 0; i <= (MCHIP_CAP(SYS_CAP_SPEC_L3IF_NUM)); i++)
        {
            p_l3if_prop = &p_usw_l3if_master[lchip]->l3if_prop[i];
            if(!p_l3if_prop->valid)
            {
                continue;
            }
            sal_memset(&egs_profile, 0, sizeof(egs_profile));
            cmd = DRV_IOR(DsDestInterface_t, DsDestInterface_routerMacProfile_f);
            CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, i, cmd, &field_val));
            egs_profile.profile_id = field_val;
            if (egs_profile.profile_id)
            {
                sal_memset(&egs_router_mac, 0, sizeof(DsEgressRouterMac_m));
                cmd = DRV_IOR(DsEgressRouterMac_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, egs_profile.profile_id, cmd, &egs_router_mac));
                egs_profile.lchip = lchip;
                egs_profile.type = 1;
                egs_profile.ds = &egs_router_mac;
                CTC_ERROR_RETURN(ctc_spool_add(p_usw_l3if_master[lchip]->macinner_spool, &egs_profile, NULL, &p_egs_get_profile));
                p_l3if_prop->egs_rtmac_index = p_egs_get_profile->profile_id;
            }
        }
    }

    if (p_usw_l3if_master[lchip]->rtmac_mode)
    {
        if (!p_tmm_l3if_rmac_entry_master[lchip])
        {
            SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Feature not initialized \n");
            return CTC_E_NOT_INIT;
        }
        /*restore rtmac entry*/
        sal_memset(&wb_rtmac, 0, sizeof(sys_wb_l3if_router_mac_entry_t));
        CTC_WB_ALLOC_BUFFER(&wb_query.buffer);
        CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_l3if_router_mac_entry_t, CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_ROUTER_MAC_ENTRY);
        CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));
            p_rtmac_entry = mem_malloc(MEM_L3IF_MODULE, sizeof(sys_l3if_rmac_entry_t));
            if (NULL == p_rtmac_entry)
            {
                return CTC_E_NO_MEMORY;
            }
            sal_memset(p_rtmac_entry, 0, sizeof(sys_l3if_rmac_entry_t));
            sal_memcpy((uint8*)&wb_rtmac, (uint8*)(wb_query.buffer) + entry_cnt * (wb_query.key_len + wb_query.data_len), wb_query.key_len + wb_query.data_len);
            entry_cnt++;

            p_rtmac_entry->fpae.offset_a = wb_rtmac.fpa_offset_a;
            p_rtmac_entry->fpae.step = 1;
            p_rtmac_entry->fpae.real_step = 1;
            p_rtmac_entry->fpae.flag = FPA_ENTRY_FLAG_INSTALLED;
            p_rtmac_entry->fpae.entry_id = wb_rtmac.entry_id;
            p_rtmac_entry->fpae.key_size = 0;
            p_rtmac_entry->fpae.priority = wb_rtmac.priority;

            p_tmm_l3if_rmac_entry_master[lchip]->rmac_block->fpab.entries[p_rtmac_entry->fpae.offset_a] = &p_rtmac_entry->fpae;
            p_tmm_l3if_rmac_entry_master[lchip]->rmac_block->fpab.free_count--;
            p_tmm_l3if_rmac_entry_master[lchip]->rmac_block->fpab.sub_free_count[0]--;

            if (NULL == ctc_hash_insert(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, p_rtmac_entry))
            {
                ret = CTC_E_NO_RESOURCE;
                goto done;
            }
        sys_usw_com_wb_restore_entry_hash(lchip, wb_rtmac.entry_id, MEM_L3IF_MODULE, p_usw_l3if_master[lchip]->rmac_pp_hash);
        CTC_WB_QUERY_ENTRY_END((&wb_query));
        CTC_WB_FREE_BUFFER(wb_query.buffer);
        return CTC_E_NONE;
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_ofb_wb_restore(lchip, p_usw_l3if_master[lchip]->ofb_type_rtmac,
                                           CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_OFB));
        /* restore ingress router mac */
        sys_usw_ofb_alloc_offset_from_position(lchip, p_usw_l3if_master[lchip]->ofb_type_rtmac, SYS_L3IF_OFB_BLK_SUB_IF, 0, NULL);
        /* 0 is reserved for system routermac, start from index 1 */
        for (i = 1; i < DRV_TABLE_MAX_INDEX(lchip, DsRouterMacTcamKey_t); i++ )
        {
            uint32 is_vartual_mac = 0;
            cmd = DRV_IOR(DsRouterMacTcamKey_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, i, cmd, &tcam_key));
            GetDsRouterMacTcamKey(A, macDa_f, tcam_key.data_entry, mac);
            cmd = DRV_IOR(DsRouterMacTcamAd_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, i, cmd, &tcam_ad));

            is_vartual_mac = GetDsRouterMacTcamAd(V, isIpv4VirtualMac_f, &tcam_ad) || GetDsRouterMacTcamAd(V, isIpv6VirtualMac_f, &tcam_ad);
            l3if_id = GetDsRouterMacTcamAd(V, routerMacId_f, &tcam_ad);
            SYS_USW_SET_USER_MAC(mac_addr, mac);
            p_l3if_prop = &p_usw_l3if_master[lchip]->l3if_prop[l3if_id];
            if (!p_l3if_prop->valid || !is_vartual_mac || !p_l3if_prop->rtmac_bmp)
            {
                continue;
            }
            CTC_ERROR_RETURN(sys_usw_ofb_alloc_offset_from_position(lchip, p_usw_l3if_master[lchip]->ofb_type_rtmac,
                                                    _sys_tmm_l3if_rtmac_get_ofb_blk_id(p_l3if_prop->l3if_type), i,NULL));
        }
        return CTC_E_NONE;
    }

done:
    return ret;
}

int32
sys_tmm_l3if_wb_rtmac_sync(uint8 lchip,uint32 app_id)
{
    int32 ret = CTC_E_NONE;
    ctc_wb_data_t wb_data;
    SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    CTC_WB_ALLOC_BUFFER(&wb_data.buffer);

    if (p_usw_l3if_master[lchip]->rtmac_mode)
    {
        if (!p_tmm_l3if_rmac_entry_master[lchip])
        {
            SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Feature not initialized \n");
            return CTC_E_NOT_INIT;
        }
        if ((app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_L3IF_SUBID_ROUTER_MAC_ENTRY) && DRV_FROM_TMM(lchip))
        {
            CTC_WB_INIT_DATA_T((&wb_data), sys_wb_l3if_router_mac_entry_t, CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_ROUTER_MAC_ENTRY);

            ctc_hash_traverse(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash, (hash_traversal_fn)_sys_tmm_l3if_wb_traverse_sync_route_mac, &wb_data);
            if (wb_data.valid_cnt > 0)
            {
                CTC_ERROR_GOTO(ctc_wb_add_entry(&wb_data), ret, done);
                wb_data.valid_cnt = 0;
            }
            CTC_WB_SYNC_END_DATA(CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_ROUTER_MAC_ENTRY);

        }
    }
    else
    {
        if ((app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_L3IF_SUBID_OFB) && DRV_FROM_TMM(lchip))
        {
            CTC_WB_INIT_DATA_T((&wb_data), sys_wb_ofb_t, CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_OFB);

            CTC_ERROR_GOTO(sys_usw_ofb_wb_sync(lchip, p_usw_l3if_master[lchip]->ofb_type_rtmac,
                                               CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_OFB, &wb_data), ret, done);
            CTC_WB_SYNC_END_DATA(CTC_FEATURE_L3IF, SYS_WB_APPID_L3IF_SUBID_OFB);
        }
    }

done:
    CTC_WB_FREE_BUFFER(wb_data.buffer);

    return ret;
}

int32
sys_tmm_l3if_dump_db(uint8 lchip, sal_file_t p_f,ctc_global_dump_db_t* p_dump_param)
{
    uint8 cnt = 1;
    uint8 mode = 1;
    uint16 i = 0;
    uint8 j = 0;
    uint8 pflag = 0;
    sys_dump_db_traverse_param_t    cb_data;
    sys_tmm_l3if_rtmac_t sw_rtmac_profile[SYS_L3IF_ROUTER_MAC_NUM_PER_IF];
    sys_l3if_prop_t* p_l3if_prop = NULL;
    sal_memset(&cb_data, 0, sizeof(sys_dump_db_traverse_param_t));

    cb_data.value0 = p_f;
    cb_data.value1 = &cnt;
    cb_data.value2 = &mode;
    cb_data.lchip = lchip;

    if (p_usw_l3if_master[lchip]->rtmac_mode)
    {
        if (!p_tmm_l3if_rmac_entry_master[lchip])
        {
            SYS_L3IF_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " Feature not initialized \n");
            return CTC_E_NOT_INIT;
        }
        SYS_DUMP_DB_LOG(p_f, "%-40s\n", "L3if Router Mac Entry:");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "--------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%-5s%-10s%-5s%-11s\n", "Cnt", "Entry id", "Pri", "Key index");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "--------------------------------------------");
        cnt = 1;
        ctc_hash_traverse(p_tmm_l3if_rmac_entry_master[lchip]->rmac_hash,(hash_traversal_fn)_sys_tmm_l3if_dump_rtmac_entry, &cb_data);
        SYS_DUMP_DB_LOG(p_f, "%s\n", "--------------------------------------------");
    }
    else
    {
        SYS_DUMP_DB_LOG(p_f, "%-40s\n", "L3if Router Mac:");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "---------------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%-5s%-9s%-16s%-11s\n", "Cnt", "l3if id", "Mac", "Key index");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "---------------------------------------------------");
        for(i = 0; i < MCHIP_CAP(SYS_CAP_SPEC_L3IF_NUM); i++)
        {
            p_l3if_prop = &p_usw_l3if_master[lchip]->l3if_prop[i];
            if(!p_l3if_prop->valid || !p_l3if_prop->rtmac_bmp)
            {
                continue;
            }

            sal_memset(sw_rtmac_profile, 0, sizeof(sw_rtmac_profile));
            CTC_ERROR_RETURN(_sys_tmm_l3if_get_rtmac_from_blk(lchip ,p_l3if_prop,sw_rtmac_profile));

            SYS_DUMP_DB_LOG(p_f, "%-5u%-9u", i, p_l3if_prop->l3if_id);
            pflag = 0;
            for (j = 0; j < SYS_L3IF_ROUTER_MAC_NUM_PER_IF; j++)
            {
                if (!CTC_IS_BIT_SET(p_l3if_prop->rtmac_bmp, j))
                {
                    continue;
                }
                if (pflag)
                {
                    SYS_DUMP_DB_LOG(p_f, "%-14s", " ");
                }
                SYS_DUMP_DB_LOG(p_f, "%-16s",
                        sys_output_mac(sw_rtmac_profile[j].mac));
                SYS_DUMP_DB_LOG(p_f, "%-11d", sw_rtmac_profile[j].key_index);
                SYS_DUMP_DB_LOG(p_f, "\n");
                pflag = 1;
            }
        }
        SYS_DUMP_DB_LOG(p_f, "%s\n", "---------------------------------------------------");
    }

    return CTC_E_NONE;
}

